package net.wanglu.www.zzz.rule.runon;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import net.wanglu.www.zzz.rule.BadEgg;
import net.wanglu.www.zzz.rule.Rule;
import net.wanglu.www.zzz.service.se.__SentenceElements;
import net.wanglu.www.zzz.service.se.expl._ExplTuple;
import net.wanglu.www.zzz.service.se.nsubj._NSubjTuple;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;

import edu.stanford.nlp.ling.IndexedWord;
import edu.stanford.nlp.ling.TaggedWord;
import edu.stanford.nlp.semgraph.SemanticGraph;
import edu.stanford.nlp.semgraph.semgrex.SemgrexMatcher;
import edu.stanford.nlp.semgraph.semgrex.SemgrexPattern;
import edu.stanford.nlp.trees.GrammaticalRelation;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeGraphNode;
import edu.stanford.nlp.trees.tregex.TregexMatcher;
import edu.stanford.nlp.trees.tregex.TregexPattern;
/*
 * 关于FusedRunon的特征
 * 第一类:
 * 1多个nsubj
 * 2各个动词之间没有依存关系或只有dep依存关系或是很勉强的ccomp依存关系
 * bug:例句17，18由于句法分析的bug(对定义从句分析不准确)而产生的bug
 * 第二类:
 * 1一个nsubj
 * 2ROOT是一个代词或名词
 * 3该代名词有rcmod依存关系
 * 4该代名词被另外一个名词修饰
 * Saturday afternoon in Kirkwood is always a busy time everyone seems to be out running errands.
 */
public class FusedRunon extends _RunonRule {

	public int Nsubj = 1;
	public int Ccomp = 2;
	
	Pattern troubleWords = Pattern.compile("\\bthen\\b|\\bhere\\b|\\bconsequently\\b|\\bfinally\\b|\\bthere\\b|\\btherefore\\b|\\busually\\b|\\bsoon\\b|\\bhowever\\b");
	Pattern startWith = Pattern.compile("^\\w");
	
	@Override
	public Object applicable(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		if ( super.applicable(objects) == Rule.Inapplicable) return Rule.Inapplicable;
		return Rule.Applicable;
	}

	@Override
	public Object deviseRightSolution(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object examine(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		HashMap<?, ?> preprocessData = (HashMap<?, ?>) objects[0];
		__SentenceElements se = (__SentenceElements) objects[1];
		
		Tree root = (Tree) preprocessData.get("root");
		SemanticGraph dependencies = (SemanticGraph) preprocessData.get("dependencies");
		List<_NSubjTuple> NSubjTupleList = se.NSubjTupleList;

		HashMap<Integer, _NSubjTuple> nsubjs = new HashMap<Integer, _NSubjTuple>(16);
		Set<TreeGraphNode> mainVerbs = new HashSet<TreeGraphNode>(16);

		for (_NSubjTuple nst : NSubjTupleList) {
			nsubjs.put(nst.getVerb().index(), nst);
			mainVerbs.add(nst.getVerb());
		}
		if ( nsubjs.size() < 2) return null;

		HashMap<_NSubjTuple, _NSubjTuple> ccompMap = new HashMap<_NSubjTuple, _NSubjTuple>(16);
		for( TreeGraphNode node : mainVerbs) {
			IndexedWord nd = dependencies.getNodeByIndexSafe(node.index());
			if ( nd == null) continue;
			
			sb.clear();
			sb.append("{tag:/VB|VBD|VBG|VBN|VBP|VBZ/}");
			sb.append("<<");
			sb.append("{");
			sb.append("tag:").append("/").append(node.label().tag()).append("/");
			sb.append(";");
			sb.append("word:").append("/").append(node.label().word()).append("/");
			sb.append("}");
			SemgrexPattern pattern = SemgrexPattern.compile(sb.toString());
			SemgrexMatcher matcher = pattern.matcher(dependencies);
			while ( matcher.find()) {
				IndexedWord node_son = matcher.getMatch();
				GrammaticalRelation gl = dependencies.reln(nd, node_son);
				if ( gl == null) {//间接联系
					nsubjs.remove(node_son.index());
				} else {//直接联系
					if ( "dep".equals(gl.getShortName())) {
						
					} else if ( "ccomp".equals(gl.getShortName())) {
						ccompMap.put(nsubjs.get(node.index()), nsubjs.get(node_son.index()));
						nsubjs.remove(node_son.index());
					} else {
						nsubjs.remove(node_son.index());
					}
				}	
			}
		}

		ArrayList<BadEgg> eggList = new ArrayList<BadEgg>(16);
		
		Collection<_NSubjTuple> nstList = nsubjs.values();
		if ( nstList.size() > 1) {
			ArrayList<String> al = new ArrayList<String>(16);
			
			for( _NSubjTuple nst : nstList) {
				
				Tree subjAncestor = nst.getSubjectAncestor();
				Tree verbAncestor = nst.getVerbAncestor();

				sb.clear();
				if ( "expl".equals(nst.getRelation())) {
					_ExplTuple et = (_ExplTuple) nst.customize();
					TreeGraphNode there = et.getExplDep();
					sb.append(there.label().word());
				} else {
					ArrayList<TaggedWord> subj_twl = subjAncestor.taggedYield();
					for( int j=0; j<subj_twl.size(); j++) {
						String word = subj_twl.get(j).word();
						if ( troubleWords.matcher(word).find()) continue;
						if ( !startWith.matcher(word).find() || "n't".equals(word)) {
							sb.append(word);
						} else {
							sb.append(" ").append(word);
						}
					}					
				}

				ArrayList<TaggedWord> verb_twl = verbAncestor.taggedYield();
				for( int j=0; j<verb_twl.size(); j++) {
					String word = verb_twl.get(j).word();
					if ( troubleWords.matcher(word).find()) continue;
					if ( !startWith.matcher(word).find() || "n't".equals(word)) {
						sb.append(word);
					} else {
						sb.append(" ").append(word);
					}
				}
				al.add(sb.toString());
			}
			
			BadEgg egg = new BadEgg();
			egg.setViolatedRule(this);
			egg.setFlag(this.Nsubj);
			egg.whereIsWrong = al;
			eggList.add(egg);
		}
		
		if ( ccompMap.size() > 0) {			
			for( Map.Entry<?, ?> entry : ccompMap.entrySet()) {
				_NSubjTuple mainNst = (_NSubjTuple) entry.getKey();
				_NSubjTuple subNst = (_NSubjTuple) entry.getValue();
				if ( mainNst == null || subNst == null) continue;
				/*
				 * --Start--判断两个动词之间是否有从属连词，如果有就认为是正常宾语从句关系，如果没有则既有可能是正常的宾语从句也有可能是接排句
				 */
				sb.clear();
				TreeGraphNode mainVerb = mainNst.getVerb();
				TreeGraphNode subVerb = subNst.getVerb();
				sb.append("/\\bSBAR\\b/");
				sb.append("$--");
				sb.append("(").append("/").append(Pattern.quote(mainVerb.label().tag())).append("/").append("<").append("/").append(Pattern.quote(mainVerb.label().word())).append("/").append(")");
				sb.append("<");
				sb.append("/\\bIN\\b|\\bWHAVP\\b|\\bWHNP\\b/");
				sb.append("<<");
				sb.append("(").append("/").append(Pattern.quote(subVerb.label().tag())).append("/").append("<").append("/").append(Pattern.quote(subVerb.label().word())).append("/").append(")");
				TregexPattern pattern = TregexPattern.compile(sb.toString());
				TregexMatcher matcher = pattern.matcher(root);
				if ( matcher.find()) continue;//matcher.find()则说明有从属连词。
				/*
				 * --End--判断两个动词之间是否有从属连词，如果有就认为是正常宾语从句关系，如果没有则既有可能是正常的宾语从句也有可能是接排句
				 */				
				Tree mainSubjAncestor = mainNst.getSubjectAncestor();
				Tree mainVerbAncestor = mainNst.getVerbAncestor();
				sb.clear();
				
				if ( "expl".equals(mainNst.getRelation())) {
					_ExplTuple et = (_ExplTuple) mainNst.customize();
					TreeGraphNode there = et.getExplDep();
					sb.append(there.label().word());
				} else {
					ArrayList<TaggedWord> mainSubj_twl = mainSubjAncestor.taggedYield();
					for( int j=0; j<mainSubj_twl.size(); j++) {
						String word = mainSubj_twl.get(j).word();
						if ( troubleWords.matcher(word).find()) continue;
						if ( !startWith.matcher(word).find() || "n't".equals(word)) {
							sb.append(word);
						} else {
							sb.append(" ").append(word);
						}
					}					
				}

				ArrayList<TaggedWord> mainVerb_twl = mainVerbAncestor.taggedYield();
				for( int j=0; j<mainVerb_twl.size(); j++) {
					String word = mainVerb_twl.get(j).word();
					if ( troubleWords.matcher(word).find()) continue;
					if ( !startWith.matcher(word).find() || "n't".equals(word)) {
						sb.append(word);
					} else {
						sb.append(" ").append(word);
					}
				}
				
				String tmp = sb.toString().trim();
				
				Tree subSubjAncestor = subNst.getSubjectAncestor();
				Tree subVerbAncestor = subNst.getVerbAncestor();
				sb.clear();
				
				if ( "expl".equals(subNst.getRelation())) {
					_ExplTuple et = (_ExplTuple) subNst.customize();
					TreeGraphNode there = et.getExplDep();
					sb.append(there.label().word());
				} else {
					ArrayList<TaggedWord> subSubj_twl = subSubjAncestor.taggedYield();
					for( int j=0; j<subSubj_twl.size(); j++) {
						String word = subSubj_twl.get(j).word();
						if ( troubleWords.matcher(word).find()) continue;
						if ( !startWith.matcher(word).find() || "n't".equals(word)) {
							sb.append(word);
						} else {
							sb.append(" ").append(word);
						}
					}					
				}

				ArrayList<TaggedWord> subVerb_twl = subVerbAncestor.taggedYield();
				for( int j=0; j<subVerb_twl.size(); j++) {
					String word = subVerb_twl.get(j).word();
					if ( troubleWords.matcher(word).find()) continue;
					if ( !startWith.matcher(word).find() || "n't".equals(word)) {
						sb.append(word);
					} else {
						sb.append(" ").append(word);
					}
				}
				
				String keyGov = mainNst.getVerb().label().word();
				
				BadEgg egg = new BadEgg();
				egg.setFlag(this.Ccomp);
				egg.setViolatedRule(this);
				egg.whereIsWrong = Pair.of(keyGov, Pair.of(StringUtils.remove(tmp, sb.toString()), sb.toString()));
				eggList.add(egg);
			}
		}
		
		if ( eggList.size() > 0) {
			return eggList;
		}
		return null;
	}
	
	@Override
	public Object whyItsWrong(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		BadEgg egg = (BadEgg) objects[0];
		
		sb.clear();
		if ( egg.getFlag() == this.Nsubj) {
			ArrayList<?> list = (ArrayList<?>) egg.whereIsWrong;
			sb.append("<p>");
			for( Object obj : list) {
				String sen = (String) obj;
				sb.append("\"").append(sen.trim()).append("\"").append("与");
			}
			sb.delete(sb.length()-1, sb.length());
			sb.append("构成了融合型接排句。");
			sb.append("它们之间应当用分号或句号隔开。");
			sb.append("</p>");
			sb.append("<p>");
			sb.append("例如:");
			sb.append("</p>");
			sb.append("<p>");
			sb.append("误:Saturday afternoon in Kirkwood is always a busy time everyone seems to be out running errands.");
			sb.append("</p>");
			sb.append("<p>");
			sb.append("正:Saturday afternoon in Kirkwood is always a busy time. Everyone seems to be out running errands.");
			sb.append("</p>");
		} else if ( egg.getFlag() == this.Ccomp) {
			Pair<?, ?> pair = (Pair<?, ?>) egg.whereIsWrong;
			String topKey = (String) pair.getKey();
			Pair<?, ?> topValue = (Pair<?, ?>) pair.getValue();
			String key = (String) topValue.getKey();
			String value = (String) topValue.getValue();
			sb.append("<p>");
			sb.append("从句");
			sb.append("\"").append(value.trim()).append("\"");
			sb.append("是");
			sb.append("\"").append(topKey.trim()).append("\"");
			sb.append("的宾语么？");
			sb.append("</p>");
			sb.append("<p>");
			sb.append("如果不是，");
			sb.append(key);
			sb.append("与");
			sb.append(value);
			sb.append("很有可能构成了融合型接排句。");
			sb.append("</p>");	
			sb.append("<p>");
			sb.append("它们之间应当用分号或句号隔开或添加某个从属连词。");
			sb.append("</p>");	
		}
		return sb.toString();
	}
}
